home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr47 / wasm223.zip / MACRO1.ASM < prev    next >
Assembly Source File  |  1993-05-04  |  44KB  |  1,750 lines

  1. ;***************************************;
  2. ; WASM Macro Processor, Compile and Run ;
  3. ; By Eric Tauck                         ;
  4. ;                                       ;
  5. ; Defines:                              ;
  6. ;                                       ;
  7. ;   MacAll  allocate macro buffers      ;
  8. ;   MacRel  release macro buffers       ;
  9. ;   MacCom  load and compile a macro    ;
  10. ;   MacRes  reset macro execution       ;
  11. ;   MacRun  run currently loaded macro  ;
  12. ;   MacAdr  return address of symbol    ;
  13. ;   MacLoa  load a stack item           ;
  14. ;   MacSto  store a stack item          ;
  15. ;   MacBug  debug flag                  ;
  16. ;                                       ;
  17. ; Requires:                             ;
  18. ;                                       ;
  19. ;   BUFFER1.ASM                         ;
  20. ;   BUFFER2.ASM                         ;
  21. ;   BUFFER4.ASM                         ;
  22. ;   CONVERT.ASM                         ;
  23. ;   MEMORY.ASM                          ;
  24. ;   STACK.ASM                           ;
  25. ;   STRING.ASM                          ;
  26. ;***************************************;
  27.  
  28.         jmp     _macro1_end
  29.  
  30. MACRO_TOKEN     EQU     33      ;maximum token size (32 characters plus NUL)
  31.  
  32. _mac_level      DW      0       ;INCLUDE nest level
  33.  
  34. ;--- error result codes
  35.  
  36. MACRO_MEMORY    EQU     1       ;not enough memory
  37. MACRO_SYMBOL    EQU     2       ;out of symbol memory
  38. MACRO_CODE      EQU     3       ;out of code memory
  39. MACRO_LONGTOK   EQU     4       ;token too long
  40. MACRO_UNDEF     EQU     5       ;undefined symbol
  41. MACRO_BADEOF    EQU     6       ;unexpected EOF after : { " ALLOC INCLUDE
  42. MACRO_FILE      EQU     7       ;error reading file
  43. MACRO_BADNUM    EQU     8       ;invalid number after ALLOC
  44.  
  45. ;--- table segment
  46.  
  47. _mac_symsiz     DW      ?       ;size
  48. _mac_symseg     DW      0       ;segment
  49. _mac_symptr     DW      ?       ;symbol pointer (grows up from beginning)
  50. _mac_fixptr     DW      ?       ;fixup pointer (grows down from end)
  51.  
  52. ;--- code segment
  53.  
  54. _mac_codsiz     DW      ?       ;size
  55. _mac_start      LABEL   DWORD
  56.                 DW      0                 ;-- code entry point
  57. _mac_codseg     DW      ?       ;segment  ;
  58. _mac_codptr     DW      ?       ;code pointer
  59.  
  60. ;--- stack segment
  61.  
  62. _mac_stksiz     DW      ?       ;size
  63. _mac_stkseg     DW      ?       ;segment
  64.  
  65. ;--- saved state
  66.  
  67. _mac_codsav     DW      ?       ;current location
  68. _mac_retsav     DW      ?       ;return pointer
  69. _mac_stksav     DW      ?       ;stack offset
  70. _mac_stksav2    DW      ?       ;saved stack offset during external call
  71.  
  72. ;--- debugging info
  73.  
  74. MacBug          DB      0       ;symbol table save flag (non-zero if save)
  75. _mac_undlen     DW      0       ;length of undefined symbol
  76. _mac_undoff     DW      0       ;offset of undefined symbol
  77.  
  78. ;--- built in words
  79.  
  80. _mac_Compiled   LABEL   BYTE
  81.         DB      ':', 0, OFFSET _mac_Define
  82.         DB      '"', 0, OFFSET _mac_String
  83.         DB      '{', 0, OFFSET _mac_Inline
  84.         DB      '//', 0, OFFSET _mac_Comment
  85.         DB      'HERE', 0, OFFSET _mac_HERE
  86.         DB      'ALLOC', 0, OFFSET _mac_ALLOC
  87.         DB      'INCLUDE', 0, OFFSET _mac_INCLUDE
  88.         DB      0
  89.  
  90. _mac_Standard   LABEL   BYTE
  91.         DB      ';', 0, OFFSET _mac_Return
  92.         DB      '!', 0, OFFSET _mac_Store
  93.         DB      '@', 0, OFFSET _mac_Fetch
  94.         DB      '+', 0, OFFSET _mac_Add
  95.         DB      '-', 0, OFFSET _mac_Subtract
  96.         DB      '*', 0, OFFSET _mac_Multiply
  97.         DB      '/', 0, OFFSET _mac_Divide
  98.         DB      'MOD',0, OFFSET _mac_MOD
  99.         DB      '/MOD',0, OFFSET _mac_dMOD
  100.         DB      'MIN',0, OFFSET _mac_MIN
  101.         DB      'MAX',0, OFFSET _mac_MAX
  102.         DB      'NEGATE',0, OFFSET _mac_NEGATE
  103.         DB      'ABS',0, OFFSET _mac_ABS
  104.         DB      '1+',0, OFFSET _mac_1Add
  105.         DB      '2+',0, OFFSET _mac_2Add
  106.         DB      '1-',0, OFFSET _mac_1Subtract
  107.         DB      '2-',0, OFFSET _mac_2Subtract
  108.         DB      '2*',0, OFFSET _mac_2Multiply
  109.         DB      '2/',0, OFFSET _mac_2Divide
  110.         DB      'DUP',0, OFFSET _mac_DUP
  111.         DB      '?DUP',0, OFFSET _mac_qDUP
  112.         DB      'DROP',0, OFFSET _mac_DROP
  113.         DB      'SWAP',0, OFFSET _mac_SWAP
  114.         DB      'OVER',0, OFFSET _mac_OVER
  115.         DB      'PICK',0, OFFSET _mac_PICK
  116.         DB      'ROT',0, OFFSET _mac_ROT
  117.         DB      '=',0, OFFSET _mac_Equal
  118.         DB      '>',0, OFFSET _mac_Greater
  119.         DB      '<',0, OFFSET _mac_Less
  120.         DB      '0=',0, OFFSET _mac_ZeroEqual
  121.         DB      '0>',0, OFFSET _mac_ZeroGreater
  122.         DB      '0<',0, OFFSET _mac_ZeroLess
  123.         DB      'FALSE',0, OFFSET _mac_FALSE
  124.         DB      'TRUE',0, OFFSET _mac_TRUE
  125.         DB      'AND',0, OFFSET _mac_AND
  126.         DB      'OR',0, OFFSET _mac_OR
  127.         DB      'NOT',0, OFFSET _mac_NOT
  128.         DB      'JUMP', 0, OFFSET _mac_JUMP
  129.         DB      '?JUMP', 0, OFFSET _mac_qJUMP
  130.         DB      'CALL', 0, OFFSET _mac_CALL
  131.         DB      '?CALL', 0, OFFSET _mac_qCALL
  132.         DB      'BREAK', 0, OFFSET _mac_BREAK
  133.         DB      'QUIT', 0, OFFSET _mac_QUIT
  134.         DB      0
  135.  
  136. ;========================================
  137. ; Determine symbol table bytes available.
  138. ;
  139. ; Out: AX= bytes available.
  140.  
  141. _mac_SymAvail PROC NEAR
  142.         mov     ax, _mac_fixptr         ;fixup pointer
  143.         sub     ax, _mac_symptr         ;symbol pointer
  144.         ret
  145.         ENDP
  146.  
  147. ;========================================
  148. ; Store a symbol.
  149. ;
  150. ; In: SI= symbol; AX= address of symbol.
  151. ;
  152. ; Out: CY= set if error.
  153.  
  154. _mac_Symbol PROC NEAR
  155.         push    di
  156.         push    si
  157.  
  158. ;--- check if space is available
  159.  
  160.         push    ax
  161.         mov     ax, si
  162.         call    StrLen          ;get string length
  163.         push    ax
  164.         call    _mac_SymAvail   ;get bytes available
  165.         pop     cx
  166.         pop     dx
  167.         mov     bx, 3
  168.         sub     ax, bx          ;reduce of length and data
  169.         jc      _mcssy1
  170.         cmp     ax, cx          ;check if room for symbol
  171.         jb      _mcssy1
  172.  
  173. ;--- store symbol and its data
  174.  
  175.         cld
  176.         mov     di, _mac_symptr ;pointer
  177.         add     bx, cx
  178.         add     bx, di          ;new pointer address
  179.         mov     _mac_symptr, bx ;save updated pointer
  180.  
  181.         push    es
  182.         mov     ax, _mac_symseg ;segment
  183.         mov     es, ax          ;new data segment
  184.         mov     al, cl
  185.         stosb                   ;store length
  186.         rep
  187.         movsb                   ;copy symbol
  188.         mov     ax, dx
  189.         stosw                   ;store data
  190.         pop     es
  191.  
  192.         pop     si
  193.         pop     di
  194.         clc
  195.         ret
  196.  
  197. ;--- out of symbol space
  198.  
  199. _mcssy1 mov     ax, MACRO_SYMBOL
  200.         pop     si
  201.         pop     di
  202.         stc
  203.         ret
  204.         ENDP
  205.  
  206. ;========================================
  207. ; Store a fixup.
  208. ;
  209. ; In: SI= symbol; AX= address of fixup.
  210. ;
  211. ; Out: CY= set if error.
  212.  
  213. _mac_Fixup PROC NEAR
  214.         push    di
  215.         push    si
  216.  
  217. ;--- check if space is available
  218.  
  219.         push    ax
  220.         mov     ax, si
  221.         call    StrLen          ;get string length
  222.         push    ax
  223.         call    _mac_SymAvail   ;get bytes available
  224.         pop     cx
  225.         pop     dx
  226.         mov     bx, 3
  227.         sub     ax, bx          ;reduce of length and data
  228.         jc      _mcfix1
  229.         cmp     ax, cx          ;check if room for symbol
  230.         jb      _mcfix1
  231.  
  232. ;--- store symbol and its data
  233.  
  234.         cld
  235.         mov     di, _mac_fixptr ;pointer
  236.         add     bx, cx
  237.         sub     di, bx          ;new pointer
  238.         mov     _mac_fixptr, di ;save updated pointer
  239.  
  240.         push    es
  241.         mov     ax, _mac_symseg ;segment
  242.         mov     es, ax          ;new data segment
  243.         mov     ax, dx
  244.         stosw                   ;store data
  245.         mov     al, cl          ;length
  246.         rep
  247.         movsb                   ;copy symbol
  248.         stosb                   ;store length
  249.         pop     es
  250.  
  251.         pop     si
  252.         pop     di
  253.         clc
  254.         ret
  255.  
  256. ;--- out of symbol space
  257.  
  258. _mcfix1 mov     ax, MACRO_SYMBOL
  259.         pop     si
  260.         pop     di
  261.         stc
  262.         ret
  263.         ENDP
  264.  
  265. ;========================================
  266. ; Look up the address of a symbol.
  267. ;
  268. ; In: AX= symbol.
  269. ;
  270. ; Out: AX= address; CY= set if not found
  271. ;      (or no symbol table).
  272.  
  273. MacAdr  PROC    NEAR
  274.         push    di
  275.         push    si
  276.         push    ds
  277.  
  278.         mov     di, ax
  279.         call    StrLen          ;get symbol length
  280.         mov     cx, ax          ;save length
  281.  
  282.         mov     ax, _mac_symseg ;load segment
  283.         or      ax, ax          ;check if any
  284.         jz      _mcadr3         ;exit if not
  285.  
  286.         cld
  287.         mov     ds, ax          ;symbol table segment
  288.         sub     si, si          ;symbol table offset
  289.         jmps    _mcadr2
  290.  
  291. ;--- loop for each symbol in table
  292.  
  293. _mcadr1 sub     ah, ah          ;AX has length
  294.         inc     ax              ;
  295.         inc     ax              ;skip address
  296.         add     si, ax          ;next symbol
  297.  
  298. _mcadr2 seg     es
  299.         cmp     si, _mac_symptr ;check if end
  300.         je      _mcadr3         ;jump if so, not found
  301.  
  302.         lodsb                   ;load length
  303.         cmp     al, cl          ;check if length matches
  304.         jne     _mcadr1         ;loop back if not
  305.         push    cx
  306.         push    di
  307.         push    si
  308.         rep
  309.         cmpsb                   ;compare strings
  310.         mov     dx, [si]        ;load address if match
  311.         pop     si
  312.         pop     di
  313.         pop     cx
  314.         jne     _mcadr1         ;loop back if different
  315.  
  316. ;--- symbol found, return address
  317.  
  318.         mov     ax, dx
  319.         pop     ds
  320.         pop     si
  321.         pop     di
  322.         clc
  323.         ret
  324.  
  325. ;---- symbol not found
  326.  
  327. _mcadr3 pop     ds
  328.         pop     si
  329.         pop     di
  330.         stc
  331.         ret
  332.         ENDP
  333.  
  334. ;========================================
  335. ; Process all fixups.
  336. ;
  337. ; Out: CY= set if error.
  338.  
  339. _mac_Fixups PROC NEAR
  340.         push    di
  341.         push    si
  342.  
  343.         StkAll  di, MACRO_TOKEN
  344.  
  345.         mov     si, _mac_symsiz         ;start of fixups
  346.         jmps    _mcfxs2                 ;enter loop
  347.  
  348. ;--- get next fixup
  349.  
  350. _mcfxs1 push    di
  351.         push    ds
  352.         mov     ax, _mac_symseg
  353.         mov     ds, ax
  354.         dec     si              ;point to length byte
  355.         mov     cl, [si]        ;length of fixup symbol
  356.         sub     ch, ch
  357.         sub     si, cx          ;start of fixup symbol
  358.  
  359.         push    cx
  360.         push    si
  361.         cld
  362.         rep
  363.         movsb                   ;copy to local storage
  364.         sub     al, al          ;zero
  365.         stosb                   ;store NUL
  366.         pop     si
  367.         pop     cx
  368.  
  369.         mov     ax, [si-2]      ;load fixup address
  370.         pop     ds
  371.         pop     di
  372.  
  373.         mov     _mac_undlen, cx ;save length of symbol
  374.         mov     _mac_undoff, si ;save offset of symbol
  375.  
  376. ;--- look up symbol
  377.  
  378.         push    ax
  379.         mov     ax, di
  380.         call    MacAdr          ;loop up symbol
  381.         pop     bx
  382.         jc      _mcfxs3         ;exit if not found
  383.  
  384. ;--- found symbol
  385.  
  386.         push    ds
  387.         mov     dx, _mac_codseg ;load load code segment
  388.         mov     ds, dx          ;
  389.         mov     [bx], ax        ;save fixup
  390.         pop     ds
  391.  
  392.         dec     si              ;next fixup symbol
  393.         dec     si              ;
  394.  
  395. ;--- next fixup
  396.  
  397. _mcfxs2 cmp     si, _mac_fixptr ;check if finished
  398.         jne     _mcfxs1
  399.  
  400.         StkRel  MACRO_TOKEN     ;fix stack
  401.         pop     si
  402.         pop     di
  403.         clc
  404.         ret
  405.  
  406. ;--- undefined symbol
  407.  
  408. _mcfxs3 mov     ax, MACRO_UNDEF         ;return error
  409.  
  410.         StkRel  MACRO_TOKEN             ;fix stack
  411.         pop     si
  412.         pop     di
  413.         stc
  414.         ret
  415.         ENDP
  416.         
  417. ;========================================
  418. ; Determine code table bytes available.
  419. ;
  420. ; Out: AX= bytes available.
  421.  
  422. _mac_CodAvail PROC NEAR
  423.         mov     ax, _mac_codsiz         ;return pointer
  424.         sub     ax, _mac_codptr         ;code pointer
  425.         ret
  426.         ENDP
  427.  
  428. ;========================================
  429. ; Store a byte to the code table.
  430. ;
  431. ; In: AL= byte.
  432. ;
  433. ; Out: CY= set if error.
  434.  
  435. _mac_CodeB PROC NEAR
  436.         push    ax
  437.         call    _mac_CodAvail   ;get bytes available
  438.         pop     dx
  439.         or      ax, ax          ;check if any
  440.         jz      _mccob1
  441.         push    ds
  442.         mov     bx, _mac_codptr ;load code pointer
  443.         mov     ds, _mac_codseg
  444.         mov     [bx], dl        ;store byte
  445.         pop     ds
  446.         inc     _mac_codptr     ;increment pointer
  447.         clc
  448.         ret
  449.  
  450. ;--- error, out of memory
  451.  
  452. _mccob1 mov     al, MACRO_CODE  ;result code
  453.         stc
  454.         ret
  455.         ENDP
  456.  
  457. ;========================================
  458. ; Store a word to the code table.
  459. ;
  460. ; In: AL= byte.
  461. ;
  462. ; Out: CY= set if error.
  463.  
  464. _mac_CodeW PROC NEAR
  465.         push    ax
  466.         call    _mac_CodeB      ;store low byte
  467.         pop     ax
  468.         jc      _mccow1
  469.         mov     al, ah
  470.         call    _mac_CodeB      ;store high byte
  471. _mccow1 ret
  472.         ENDP
  473.  
  474. ;========================================
  475. ; Store a code routine.
  476. ;
  477. ; In: AX= address of routine.
  478. ;
  479. ; Out: CY= set if error.
  480.  
  481. _mac_Code PROC  NEAR
  482.         push    si
  483.         mov     si, ax
  484.  
  485.         mov     cx, [si]        ;load size of code
  486.         inc     si              ;
  487.         inc     si              ;skip length
  488.  
  489. _mccod1 cld
  490.         lodsb                   ;load byte
  491.         push    cx
  492.         call    _mac_CodeB      ;store byte
  493.         pop     cx
  494.         jc      _mccod2         ;exit if error
  495.         loop    _mccod1         ;loop for each byte
  496. _mccod2 pop     si
  497.         ret
  498.         ENDP
  499.  
  500. ;========================================
  501. ; Search for a symbol.
  502. ;
  503. ; In: SI= symbol; AX= symbol table.
  504. ;
  505. ; Out: CY= cleared if found; AX= data.
  506.  
  507. _mac_Search PROC  NEAR
  508.         push    di
  509.         mov     di, ax
  510.         jmps    _mcsea2
  511.  
  512. ;--- skip of reset of table entry
  513.  
  514. _mcsea1 sub     al, al          ;search for NUL
  515.         cld
  516.         mov     cx, 0FFFFH
  517.         repne
  518.         scasb                   ;scan
  519.         inc     di
  520.         inc     di              ;skip rest of value
  521.  
  522. ;--- compare entry
  523.  
  524. _mcsea2 cmp     BYTE [di], 0    ;check if end of table
  525.         je      _mcsea5         ;exit if so
  526.         sub     bx, bx          ;zero index
  527.         jmps    _mcsea4
  528.  
  529. ;--- loop for each character
  530.  
  531. _mcsea3 inc     di              ;increment table pointer
  532.         inc     bx              ;increment index
  533. _mcsea4 mov     al, [si+bx]     ;load source character
  534.         cmp     al, [di]        ;check if match
  535.         jne     _mcsea1         ;goto next entry if not
  536.         or      al, al          ;check if end of strings
  537.         jnz     _mcsea3         ;loop back if not
  538.  
  539. ;--- found
  540.  
  541.         mov     ax, [di+1]      ;load table value
  542.         pop     di
  543.         clc
  544.         ret
  545.  
  546. ;--- not found
  547.  
  548. _mcsea5 pop     di
  549.         stc
  550.         ret
  551.         ENDP
  552.  
  553. ;========================================
  554. ; Compiled words.
  555.  
  556. ;=== define a symbol
  557.  
  558. _mac_Define PROC NEAR
  559.         mov     ax, si
  560.         mov     cx, MACRO_TOKEN
  561.         mov     bx, di
  562.         call    GetTok          ;get symbol
  563.         jc      _mcdef1         ;exit if error
  564.         or      ax, ax          ;check if EOF
  565.         jz      _mcdef3         ;exit if so
  566.         mov     ax, _mac_codptr ;address
  567.         call    _mac_Symbol     ;put in symbol table
  568.         ret
  569.  
  570. ;--- error reading token
  571.  
  572. _mcdef1 or      ax, ax          ;check if DOS error
  573.         jnz     _mcdef2         ;jump if so
  574.         mov     ax, MACRO_LONGTOK
  575.         stc
  576.         ret
  577.  
  578. _mcdef2 mov     ax, MACRO_FILE
  579.         stc
  580.         ret
  581.  
  582. _mcdef3 mov     ax, MACRO_BADEOF
  583.         stc
  584.         ret
  585.         ENDP
  586.  
  587. ;=== store a string
  588.  
  589. _mac_String PROC NEAR
  590.         jmps    _mcstr2
  591.  
  592. _mcstr1 call    _mac_CodeB      ;store byte
  593.         jc      _mcstr3         ;exit if error
  594.  
  595. _mcstr2 mov     bx, di
  596.         call    GetByt          ;get a byte
  597.         jc      _mcstr6
  598.         cmp     al, 32          ;check if delimiter
  599.         jb      _mcstr2
  600.         cmp     al, '^'         ;check if control character
  601.         je      _mcstr4
  602.         cmp     al, '\'         ;check if mask character
  603.         je      _mcstr5
  604.         cmp     al, '"'         ;check if end of string
  605.         jne     _mcstr1
  606.  
  607.         sub     al, al          ;NUL
  608.         call    _mac_CodeB      ;store byte
  609. _mcstr3 ret
  610.  
  611. ;--- control character
  612.  
  613. _mcstr4 mov     bx, di
  614.         call    GetByt          ;get byte
  615.         jc      _mcstr6
  616.         call    ChrUpr          ;convert to uppercase
  617.         sub     al, 64          ;translate to control code
  618.         jmps    _mcstr1
  619.  
  620. ;--- mask character
  621.  
  622. _mcstr5 mov     bx, di
  623.         call    GetByt          ;get byte
  624.         jnc     _mcstr1
  625.  
  626. ;--- error reading byte
  627.  
  628. _mcstr6 or      al, al          ;check if DOS error
  629.         jnz     _mcstr7         ;jump if so
  630.         mov     ax, MACRO_BADEOF
  631.         stc
  632.         ret
  633.  
  634. _mcstr7 mov     ax, MACRO_FILE
  635.         stc
  636.         ret
  637.         ENDP
  638.  
  639. ;=== inline code
  640.  
  641. _mac_Inline PROC NEAR
  642.  
  643. ;--- loop for each token in { }
  644.  
  645. _mcinl1 mov     ax, si
  646.         mov     cx, MACRO_TOKEN
  647.         mov     bx, di
  648.         call    GetTok          ;get data
  649.         jc      _mcinl4         ;exit if error
  650.         or      ax, ax          ;check if EOF
  651.         jz      _mcinl6         ;exit if so
  652.  
  653.         cmp     WORD [si],007DH ;check if end of data: '}',0
  654.         je      _mcinl3         ;exit loop if so
  655.  
  656. ;--- check if number
  657.  
  658.         call    _mac_GetNumber  ;interpret as number
  659.         jnc     _mcinl2         ;jump if okay
  660.  
  661. ;--- must be symbol reference
  662.  
  663.         mov     ax, _mac_codptr
  664.         call    _mac_Fixup      ;store fixup
  665.         sub     ax, ax
  666.  
  667. _mcinl2 call    _mac_CodeW      ;code a word
  668.         jnc     _mcinl1         ;loop back if no error
  669.  
  670. _mcinl3 ret
  671.  
  672. ;--- error
  673.  
  674. _mcinl4 or      ax, ax          ;check if DOS error
  675.         jnz     _mcinl5         ;jump if so
  676.         mov     ax, MACRO_LONGTOK
  677.         stc
  678.         ret
  679.  
  680. _mcinl5 mov     ax, MACRO_FILE
  681.         stc
  682.         ret
  683.  
  684. _mcinl6 mov     ax, MACRO_BADEOF
  685.         stc
  686.         ret
  687.         ENDP
  688.  
  689. ;=== skip a comment
  690.  
  691. _mac_Comment PROC NEAR
  692. _mccmm1 mov     bx, di
  693.         call    GetByt          ;get a byte
  694.         jc      _mccmm3         ;jump if error
  695.         cmp     al, 13          ;check if CR
  696.         je      _mccmm2
  697.         cmp     al, 10          ;check if LF
  698.         jne     _mccmm1
  699. _mccmm2 clc
  700.         ret
  701.  
  702. ;--- error reading byte
  703.  
  704. _mccmm3 or      al, al          ;check if DOS error
  705.         jz      _mccmm2         ;jump if EOF, no error
  706.         mov     ax, MACRO_FILE
  707.         stc
  708.         ret
  709.         ENDP
  710.  
  711. ;=== push current address
  712.  
  713. _mac_HERE PROC NEAR
  714.         mov     ax, _mac_codptr ;current location
  715.         add     ax, 4           ;skip the HERE code
  716.         call    _mac_Number     ;push a number
  717.         ret
  718.         ENDP
  719.  
  720. ;=== allocate space
  721.  
  722. _mac_ALLOC PROC NEAR
  723.         mov     ax, si
  724.         mov     cx, MACRO_TOKEN
  725.         mov     bx, di
  726.         call    GetTok          ;get amount of space
  727.         jc      _mcalc4         ;exit if error
  728.         or      ax, ax          ;check if EOF
  729.         jz      _mcalc6         ;exit if so
  730.         call    _mac_GetNumber  ;interpret number
  731.         jc      _mcalc7         ;jump if error
  732.  
  733. ;--- store bytes of code
  734.  
  735.         mov     cx, ax
  736.         jcxz    _mcalc2         ;exit if no bytes
  737.  
  738. _mcalc1 push    cx
  739.         sub     al, al
  740.         call    _mac_CodeB      ;store a zero
  741.         pop     cx
  742.         jc      _mcalc3         ;exit if error
  743.         loop    _mcalc1         ;loop for all bytes
  744. _mcalc2 clc
  745. _mcalc3 ret
  746.  
  747. ;--- error reading token
  748.  
  749. _mcalc4 or      ax, ax          ;check if DOS error
  750.         jnz     _mcalc5         ;jump if so
  751.         mov     ax, MACRO_LONGTOK
  752.         stc
  753.         ret
  754.  
  755. _mcalc5 mov     ax, MACRO_FILE
  756.         stc
  757.         ret
  758.  
  759. _mcalc6 mov     ax, MACRO_BADEOF
  760.         stc
  761.         ret
  762.  
  763. _mcalc7 mov     ax, MACRO_BADNUM
  764.         stc
  765.         ret
  766.         ENDP
  767.  
  768. ;=== include file
  769.  
  770. _mac_INCLUDE PROC NEAR
  771.         mov     ax, si
  772.         mov     cx, MACRO_TOKEN
  773.         mov     bx, di
  774.         call    GetTok          ;get data
  775.         jc      _mcinc1         ;exit if error
  776.         or      ax, ax          ;check if EOF
  777.         jz      _mcinc3         ;exit if so
  778.  
  779.         mov     ax, si
  780.         inc     _mac_level
  781.         call    MacCom          ;compile without initialization
  782.         dec     _mac_level
  783.         ret
  784.  
  785. ;--- error
  786.  
  787. _mcinc1 or      ax, ax          ;check if DOS error
  788.         jnz     _mcinc2         ;jump if so
  789.         mov     ax, MACRO_LONGTOK
  790.         stc
  791.         ret
  792.  
  793. _mcinc2 mov     ax, MACRO_FILE
  794.         stc
  795.         ret
  796.  
  797. _mcinc3 mov     ax, MACRO_BADEOF
  798.         stc
  799.         ret
  800.         ENDP
  801.  
  802. ;=== push a number, In: AX= number
  803.  
  804. _mac_Number PROC NEAR
  805.         mov     [OFFSET _mac_Load + 3], ax
  806.         mov     ax, OFFSET _mac_Load
  807.         call    _mac_Code
  808.         ret
  809.         ENDP
  810.  
  811. ;=== push a symbol address
  812.  
  813. _mac_Reference PROC NEAR
  814.         call    _mac_Number
  815.         mov     ax, _mac_codptr
  816.         sub     ax, 3
  817.         call    _mac_Fixup
  818.         ret
  819.         ENDP
  820.  
  821. ;=== external symbol reference
  822.  
  823. _mac_External PROC NEAR
  824.         mov     [OFFSET _mac_LongCall + 3], ax
  825.         mov     ax, OFFSET _mac_LongCall
  826.         call    _mac_Code
  827.         ret
  828.         ENDP
  829.  
  830. ;========================================
  831. ; Standard words.
  832.  
  833. ;=== startup code
  834.  
  835. _mac_Startup
  836.         DW      OFFSET _mac_Startupx - OFFSET _mac_Startup - 2
  837. _mcsta1 EQU     $
  838.         ORG     0
  839.  
  840. ;--- entry code, expects real start address in AX
  841.  
  842.         pop     dx
  843.         mov     [_mcrets], dx
  844.         pop     dx
  845.         mov     [_mcreto], dx
  846.         push    ax
  847.         retn
  848.  
  849. ;--- external hook routine, expects external address in DX:AX
  850.  
  851. _mccal  mov     WORD _mcextr, ax        ;save target address
  852.         mov     WORD _mcextr + 2, dx    ;
  853.  
  854.         push    es                      ;load data segment
  855.         pop     ds                      ;
  856.  
  857.         mov     _mac_stksav2, sp        ;save stack offset
  858.  
  859.         cli
  860.         mov     ax, _mac_oldseg
  861.         mov     ss, ax
  862.         mov     sp, _mac_oldoff
  863.         sti
  864.  
  865.         seg     cs
  866.         call    _mcextr                 ;call external routine
  867.  
  868.         cli
  869.         mov     ax, _mac_stkseg
  870.         mov     ss, ax
  871.         mov     sp, _mac_stksav2
  872.         sti
  873.  
  874.         push    cs                      ;
  875.         pop     ds                      ;reload data segment
  876.         retn
  877.  
  878. ;--- data
  879.  
  880. _mcrets DW      0                       ;return segment
  881. _mcreto DW      0                       ;return offset
  882. _mcextr LABEL   DWORD                   ;external routine location
  883.         DW      0, 0
  884. _mcstar ORG     $ + _mcsta1
  885. _mac_Startupx
  886.  
  887. ;=== load a number to the stack, the number must be set
  888.  
  889. _mac_Load
  890.         DW      OFFSET _mac_Loadx - OFFSET _mac_Load - 2
  891.         mov     ax, 0
  892.         push    ax
  893. _mac_Loadx
  894.  
  895. ;=== call an externl routine, the offset and segment must be set
  896.  
  897. _mac_LongCall
  898.         DW      OFFSET _mac_LongCallx - OFFSET _mac_LongCall - 2
  899.         mov     ax, 0
  900.         mov     dx, es
  901.         mov     bx, OFFSET _mccal
  902.         call    bx
  903. _mac_LongCallx
  904.  
  905. ;=== return from a routine
  906.  
  907. _mac_Return
  908.         DW      OFFSET _mac_Returnx - OFFSET _mac_Return - 2
  909.         inc     si
  910.         inc     si
  911.         jmp     WORD [si]
  912. _mac_Returnx
  913.  
  914. ;=== store a value to an address
  915.  
  916. _mac_Store
  917.         DW      OFFSET _mac_Storex - OFFSET _mac_Store - 2
  918.         pop     bx
  919.         pop     ax
  920.         mov     [bx], ax
  921. _mac_Storex
  922.  
  923. ;=== load a number from an address
  924.  
  925. _mac_Fetch
  926.         DW      OFFSET _mac_Fetchx - OFFSET _mac_Fetch - 2
  927.         pop     bx
  928.         push    WORD [bx]
  929. _mac_Fetchx
  930.  
  931. ;=== add two numbers
  932.  
  933. _mac_Add
  934.         DW      OFFSET _mac_Addx - OFFSET _mac_Add - 2
  935.         pop     bx
  936.         pop     ax
  937.         add     ax, bx
  938.         push    ax
  939. _mac_Addx
  940.  
  941. ;=== subtract two numbers
  942.  
  943. _mac_Subtract
  944.         DW      OFFSET _mac_Subtractx - OFFSET _mac_Subtract - 2
  945.         pop     bx
  946.         pop     ax
  947.         sub     ax, bx
  948.         push    ax
  949. _mac_Subtractx
  950.  
  951. ;=== multiply two numbers
  952.  
  953. _mac_Multiply
  954.         DW      OFFSET _mac_Multiplyx - OFFSET _mac_Multiply - 2
  955.         pop     ax
  956.         pop     dx
  957.         imul    ax, dx
  958.         push    ax
  959. _mac_Multiplyx
  960.  
  961. ;=== divide two numbers
  962.  
  963. _mac_Divide
  964.         DW      OFFSET _mac_Dividex - OFFSET _mac_Divide - 2
  965.         pop     bx
  966.         pop     ax
  967.         sub     dx, dx
  968.         idiv    ax, bx
  969.         push    ax
  970. _mac_Dividex
  971.  
  972. ;=== divide two numbers, return only remainder
  973.  
  974. _mac_MOD
  975.         DW      OFFSET _mac_MODx - OFFSET _mac_MOD - 2
  976.         pop     bx
  977.         pop     ax
  978.         sub     dx, dx
  979.         idiv    ax, bx
  980.         push    dx
  981. _mac_MODx
  982.  
  983. ;=== divide two numbers, return quotient and remainder
  984.  
  985. _mac_dMOD
  986.         DW      OFFSET _mac_dMODx - OFFSET _mac_dMOD - 2
  987.         pop     bx
  988.         pop     ax
  989.         sub     dx, dx
  990.         idiv    ax, bx
  991.         push    dx
  992.         push    ax
  993. _mac_dMODx
  994.  
  995. ;=== return minimum of two numbers
  996.  
  997. _mac_MIN
  998.         DW      OFFSET _mac_MINx - OFFSET _mac_MIN - 2
  999.         pop     ax
  1000.         pop     dx
  1001.         cmp     ax, dx
  1002.         jle     _mcmin1
  1003.         mov     ax, dx
  1004. _mcmin1 push    ax
  1005. _mac_MINx
  1006.  
  1007. ;=== return the maximum of two numbers
  1008.  
  1009. _mac_MAX
  1010.         DW      OFFSET _mac_MAXx - OFFSET _mac_MAX - 2
  1011.         pop     ax
  1012.         pop     dx
  1013.         cmp     ax, dx
  1014.         jge     _mcmax1
  1015.         mov     ax, dx
  1016. _mcmax1 push    ax
  1017. _mac_MAXx
  1018.  
  1019. ;=== negate a number
  1020.  
  1021. _mac_NEGATE
  1022.         DW      OFFSET _mac_NEGATEx - OFFSET _mac_NEGATE - 2
  1023.         pop     ax
  1024.         neg     ax
  1025.         push    ax
  1026. _mac_NEGATEx
  1027.  
  1028. ;=== return the absolute value of a number
  1029.  
  1030. _mac_ABS
  1031.         DW      OFFSET _mac_ABSx - OFFSET _mac_ABS - 2
  1032.         pop     ax
  1033.         cmp     ax, 0
  1034.         jge     _mcabs1
  1035.         neg     ax
  1036. _mcabs1 push    ax
  1037. _mac_ABSx
  1038.  
  1039. ;=== increment a number
  1040.  
  1041. _mac_1Add
  1042.         DW      OFFSET _mac_1Addx - OFFSET _mac_1Add - 2
  1043.         pop     ax
  1044.         inc     ax
  1045.         push    ax
  1046. _mac_1Addx
  1047.  
  1048. ;=== add two to a number
  1049.  
  1050. _mac_2Add
  1051.         DW      OFFSET _mac_2Addx - OFFSET _mac_2Add - 2
  1052.         pop     ax
  1053.         inc     ax
  1054.         inc     ax
  1055.         push    ax
  1056. _mac_2Addx
  1057.  
  1058. ;=== decrement a number
  1059.  
  1060. _mac_1Subtract
  1061.         DW      OFFSET _mac_1Subtractx - OFFSET _mac_1Subtract - 2
  1062.         pop     ax
  1063.         dec     ax
  1064.         push    ax
  1065. _mac_1Subtractx
  1066.  
  1067. ;=== subtract two from a number
  1068.  
  1069. _mac_2Subtract
  1070.         DW      OFFSET _mac_2Subtractx - OFFSET _mac_2Subtract - 2
  1071.         pop     ax
  1072.         dec     ax
  1073.         dec     ax
  1074.         push    ax
  1075. _mac_2Subtractx
  1076.  
  1077. ;=== multiply a number times two
  1078.  
  1079. _mac_2Multiply
  1080.         DW      OFFSET _mac_2Multiplyx - OFFSET _mac_2Multiply - 2
  1081.         pop     ax
  1082.         shl     ax
  1083.         push    ax
  1084. _mac_2Multiplyx
  1085.  
  1086. ;=== divide a number by two
  1087.  
  1088. _mac_2Divide
  1089.         DW      OFFSET _mac_2Dividex - OFFSET _mac_2Divide - 2
  1090.         pop     ax
  1091.         shr     ax
  1092.         push    ax
  1093. _mac_2Dividex
  1094.  
  1095. ;=== duplicate an item
  1096.  
  1097. _mac_DUP
  1098.         DW      OFFSET _mac_DUPx - OFFSET _mac_DUP - 2
  1099.         pop     ax
  1100.         push    ax
  1101.         push    ax
  1102. _mac_DUPx
  1103.  
  1104. ;=== duplicate an item if non-zero
  1105.  
  1106. _mac_qDUP
  1107.         DW      OFFSET _mac_qDUPx - OFFSET _mac_qDUP - 2
  1108.         pop     ax
  1109.         or      ax, ax
  1110.         jz      _mcqdu1
  1111.         push    ax
  1112. _mcqdu1 push    ax
  1113. _mac_qDUPx
  1114.  
  1115. ;=== drop an item
  1116.  
  1117. _mac_DROP
  1118.         DW      OFFSET _mac_DROPx - OFFSET _mac_DROP - 2
  1119.         pop     ax
  1120. _mac_DROPx
  1121.  
  1122. ;=== swap top two items
  1123.  
  1124. _mac_SWAP
  1125.         DW      OFFSET _mac_SWAPx - OFFSET _mac_SWAP - 2
  1126.         pop     ax
  1127.         pop     dx
  1128.         push    ax
  1129.         push    dx
  1130. _mac_SWAPx
  1131.  
  1132. ;=== copy second item down to top of stack
  1133.  
  1134. _mac_OVER
  1135.         DW      OFFSET _mac_OVERx - OFFSET _mac_OVER - 2
  1136.         pop     ax
  1137.         pop     dx
  1138.         push    ax
  1139.         push    dx
  1140.         push    ax
  1141. _mac_OVERx
  1142.  
  1143. ;=== copy an indexed item down to the the top of the stack
  1144.  
  1145. _mac_PICK
  1146.         DW      OFFSET _mac_PICKx - OFFSET _mac_PICK - 2
  1147.         pop     di
  1148.         shl     di
  1149.         mov     bp, sp
  1150.         push    WORD [bp + di]
  1151. _mac_PICKx
  1152.  
  1153. ;=== rotate top three items
  1154.  
  1155. _mac_ROT
  1156.         DW      OFFSET _mac_ROTx - OFFSET _mac_ROT - 2
  1157.         pop     ax
  1158.         pop     bx
  1159.         pop     cx
  1160.         push    bx
  1161.         push    ax
  1162.         push    cx
  1163. _mac_ROTx
  1164.  
  1165. ;=== check if a number is equal to another number
  1166.  
  1167. _mac_Equal
  1168.         DW      OFFSET _mac_Equalx - OFFSET _mac_Equal - 2
  1169.         pop     ax
  1170.         pop     dx
  1171.         sub     bx, bx
  1172.         cmp     ax, dx
  1173.         jne     _mcequ1
  1174.         dec     bx
  1175. _mcequ1 push    bx
  1176. _mac_Equalx
  1177.  
  1178. ;=== check if a number is greater than another number
  1179.  
  1180. _mac_Greater
  1181.         DW      OFFSET _mac_Greaterx - OFFSET _mac_Greater - 2
  1182.         pop     ax
  1183.         pop     dx
  1184.         sub     bx, bx
  1185.         cmp     dx, ax
  1186.         jle     _mcgre1
  1187.         dec     bx
  1188. _mcgre1 push    bx
  1189. _mac_Greaterx
  1190.  
  1191. ;=== check if a number is less than another number
  1192.  
  1193. _mac_Less
  1194.         DW      OFFSET _mac_Lessx - OFFSET _mac_Less - 2
  1195.         pop     ax
  1196.         pop     dx
  1197.         sub     bx, bx
  1198.         cmp     dx, ax
  1199.         jge     _mcles1
  1200.         dec     bx
  1201. _mcles1 push    bx
  1202. _mac_Lessx
  1203.  
  1204. ;=== check if a number is equal to zero
  1205.  
  1206. _mac_ZeroEqual
  1207.         DW      OFFSET _mac_ZeroEqualx - OFFSET _mac_ZeroEqual - 2
  1208.         pop     ax
  1209.         sub     bx, bx
  1210.         or      ax, ax
  1211.         jnz     _mczeq1
  1212.         dec     bx
  1213. _mczeq1 push    bx
  1214. _mac_ZeroEqualx
  1215.  
  1216. ;=== check if a number is greater than zero
  1217.  
  1218. _mac_ZeroGreater
  1219.         DW      OFFSET _mac_ZeroGreaterx - OFFSET _mac_ZeroGreater - 2
  1220.         pop     ax
  1221.         sub     bx, bx
  1222.         cmp     ax, 0
  1223.         jle     _mczgr1
  1224.         dec     bx
  1225. _mczgr1 push    bx
  1226. _mac_ZeroGreaterx
  1227.  
  1228. ;=== check if a number is less than zero
  1229.  
  1230. _mac_ZeroLess
  1231.         DW      OFFSET _mac_ZeroLessx - OFFSET _mac_ZeroLess - 2
  1232.         pop     ax
  1233.         sub     bx, bx
  1234.         cmp     ax, 0
  1235.         jge     _mczle1
  1236.         dec     bx
  1237. _mczle1 push    bx
  1238. _mac_ZeroLessx
  1239.  
  1240. ;=== load FALSE (zero)
  1241.  
  1242. _mac_FALSE
  1243.         DW      OFFSET _mac_FALSEx - OFFSET _mac_FALSE - 2
  1244.         sub     ax, ax
  1245.         push    ax
  1246. _mac_FALSEx
  1247.  
  1248. ;=== load TRUE ($FFFF)
  1249.  
  1250. _mac_TRUE
  1251.         DW      OFFSET _mac_TRUEx - OFFSET _mac_TRUE - 2
  1252.         mov     ax, -1
  1253.         push    ax
  1254. _mac_TRUEx
  1255.  
  1256. ;=== AND two numbers
  1257.  
  1258. _mac_AND
  1259.         DW      OFFSET _mac_ANDx - OFFSET _mac_AND - 2
  1260.         pop     ax
  1261.         pop     dx
  1262.         and     ax, dx
  1263.         push    ax
  1264. _mac_ANDx
  1265.  
  1266. ;=== OR two numbers
  1267.  
  1268. _mac_OR
  1269.         DW      OFFSET _mac_ORx - OFFSET _mac_OR - 2
  1270.         pop     ax
  1271.         pop     dx
  1272.         or      ax, dx
  1273.         push    ax
  1274. _mac_ORx
  1275.  
  1276. ;=== NOT a number
  1277.  
  1278. _mac_NOT
  1279.         DW      OFFSET _mac_NOTx - OFFSET _mac_NOT - 2
  1280.         pop     ax
  1281.         not     ax
  1282.         push    ax
  1283. _mac_NOTx
  1284.  
  1285. ;=== jump to an address
  1286.  
  1287. _mac_JUMP
  1288.         DW      OFFSET _mac_JUMPx - OFFSET _mac_JUMP - 2
  1289.         retn
  1290. _mac_JUMPx
  1291.  
  1292. ;=== jump to an address if condition is true
  1293.  
  1294. _mac_qJUMP
  1295.         DW      OFFSET _mac_qJUMPx - OFFSET _mac_qJUMP - 2
  1296.         pop     dx
  1297.         pop     ax
  1298.         or      ax, ax
  1299.         jz      _mac_qJUMPx
  1300.         jmp     dx
  1301. _mac_qJUMPx
  1302.  
  1303. ;=== call a routine
  1304.  
  1305. _mac_CALL
  1306.         DW      OFFSET _mac_CALLx - OFFSET _mac_CALL - 2
  1307.         call    _mccal1
  1308. _mccal1 pop     ax
  1309.         add     ax, OFFSET _mac_CALLx - OFFSET _mccal1
  1310.         mov     [si], ax
  1311.         dec     si
  1312.         dec     si
  1313.         retn
  1314. _mac_CALLx
  1315.  
  1316. ;=== call a routine if a contition is true
  1317.  
  1318. _mac_qCALL
  1319.         DW      OFFSET _mac_qCALLx - OFFSET _mac_qCALL - 2
  1320.         pop     dx
  1321.         pop     ax
  1322.         or      ax, ax
  1323.         jz      _mac_qCALLx
  1324.         call    _mcqca1
  1325. _mcqca1 pop     ax
  1326.         add     ax, OFFSET _mac_qCALLx - OFFSET _mcqca1
  1327.         mov     [si], ax
  1328.         dec     si
  1329.         dec     si
  1330.         jmp     dx
  1331. _mac_qCALLx
  1332.  
  1333. ;=== break into a macro
  1334.  
  1335. _mac_BREAK
  1336.         DW      OFFSET _mac_BREAKx - OFFSET _mac_BREAK - 2
  1337.         push    WORD [_mcreto]
  1338.         push    WORD [_mcrets]
  1339.         call    _mcbrk1
  1340. _mcbrk1 pop     ax
  1341.         add     ax, 6
  1342.         stc
  1343.         retf
  1344. _mac_BREAKx
  1345.  
  1346. ;=== quit a macro
  1347.  
  1348. _mac_QUIT
  1349.         DW      OFFSET _mac_QUITx - OFFSET _mac_QUIT - 2
  1350.         push    WORD [_mcreto]
  1351.         push    WORD [_mcrets]
  1352.         clc
  1353.         retf
  1354. _mac_QUITx
  1355.  
  1356. ;========================================
  1357. ; Try to translate token into number.
  1358. ;
  1359. ; In: SI= token buffer.
  1360. ;
  1361. ; Out: CY= clear if number; AX= value.
  1362.  
  1363. _mac_GetNumber PROC NEAR
  1364.  
  1365. ;=== check if quoted character
  1366.  
  1367.         cmp     BYTE [si], 39
  1368.         jne     _mcgnu1
  1369.         cmp     BYTE [si+1], 0
  1370.         je      _mcgnu1
  1371.         cmp     BYTE [si+2], 39
  1372.         jne     _mcgnu1
  1373.         cmp     BYTE [si+3], 0
  1374.         jne     _mcgnu1
  1375.  
  1376.         mov     al, [si+1]
  1377.         sub     ah, ah
  1378.         clc
  1379.         ret
  1380.  
  1381. ;=== check if number
  1382.  
  1383. ;--- sign
  1384.  
  1385. _mcgnu1 push    si
  1386.         cmp     BYTE [si], '+'  ;check if plus
  1387.         je      _mcgnu2
  1388.         cmp     BYTE [si], '-'  ;check if minus
  1389.         jne     _mcgnu3
  1390. _mcgnu2 inc     si              ;skip sign
  1391.  
  1392. ;--- hex / decimal
  1393.  
  1394. _mcgnu3 mov     cx, 10          ;base 10
  1395.         cmp     BYTE [si], '$'  ;check if hex number
  1396.         jne     _mcgnu4         ;skip if not
  1397.         mov     cx, 16          ;base 16
  1398.         inc     si              ;skip $
  1399.  
  1400. ;--- convert number
  1401.  
  1402. _mcgnu4 mov     ax, si
  1403.         call    Str2Num         ;convert to number
  1404.         pop     si
  1405.         jc      _mcgnu6         ;exit if error
  1406.         cmp     BYTE [si], '-'  ;check if negative
  1407.         jne     _mcgnu5         ;skip if not
  1408.         neg     ax              ;make it negative
  1409. _mcgnu5 clc
  1410. _mcgnu6 ret
  1411.         ENDP
  1412.  
  1413. ;========================================
  1414. ; Process a token.
  1415. ;
  1416. ; In: SI= token buffer; DI= input record.
  1417. ;
  1418. ; Out: CY= set if error.
  1419.  
  1420. _mac_Token PROC NEAR
  1421.         call    _mac_GetNumber
  1422.         jc      _mctok1
  1423.         call    _mac_Number
  1424.         ret
  1425.  
  1426. ;--- check if compiled token
  1427.  
  1428. _mctok1 mov     ax, OFFSET _mac_Compiled
  1429.         call    _mac_Search
  1430.         jc      _mctok2
  1431.         call    ax
  1432.         ret
  1433.  
  1434. ;--- check if standard token
  1435.  
  1436. _mctok2 mov     ax, OFFSET _mac_Standard
  1437.         call    _mac_Search
  1438.         jc      _mctok3
  1439.         call    _mac_Code
  1440.         ret
  1441.  
  1442. ;--- check if user symbol
  1443.  
  1444. _mctok3 mov     ax, OFFSET MacUsr
  1445.         call    _mac_Search
  1446.         jc      _mctok4
  1447.         call    _mac_External
  1448.         ret
  1449.  
  1450. ;--- must be symbol, make a reference
  1451.  
  1452. _mctok4 call    _mac_Reference
  1453.         ret
  1454.         ENDP
  1455.  
  1456. ;========================================
  1457. ; Allocate macro memory.
  1458. ;
  1459. ; In: AX= size of code table; BX= size of
  1460. ;     stack; CX= size of symbol table.
  1461. ;
  1462. ; Out: CY= set of not enough memory.
  1463.  
  1464. MacAll  PROC    NEAR
  1465.         mov     _mac_symsiz, cx ;save size, do not allocate
  1466.  
  1467. ;--- allocate code and stack segments
  1468.  
  1469.         push    bx
  1470.         call    MemAll          ;allocate
  1471.         mov     _mac_codseg, ax ;save segment
  1472.         mov     _mac_codsiz, dx ;save size
  1473.         pop     ax
  1474.         jc      _mcall1
  1475.  
  1476.         call    MemAll          ;allocate
  1477.         mov     _mac_stkseg, ax ;save segment
  1478.         mov     _mac_stksiz, dx ;save size
  1479.  
  1480. _mcall1 ret
  1481.         ENDP
  1482.  
  1483. ;========================================
  1484. ; Release macro memory.
  1485.  
  1486. MacRel  PROC    NEAR
  1487.         mov     ax, _mac_symseg
  1488.         or      ax, ax
  1489.         jz      _mcrel1
  1490.         call    MemRel          ;release symbol segment
  1491. _mcrel1 mov     ax, _mac_stkseg
  1492.         call    MemRel          ;release stack segment
  1493.         mov     ax, _mac_codseg
  1494.         call    MemRel          ;release code segment
  1495.         ret
  1496.         ENDP
  1497.  
  1498. ;========================================
  1499. ; Load and compile a macro file.
  1500. ;
  1501. ; In: AX= file name.
  1502. ;
  1503. ; Out: CY= set if error; AX= result code
  1504. ;      if error.
  1505.  
  1506. MacCom  PROC NEAR
  1507.         push    di
  1508.         push    si
  1509.         push    bp
  1510.  
  1511.         StkAll  di, BUFFER_RECORD       ;buffer record
  1512.         StkAll  si, MACRO_TOKEN         ;token buffer
  1513.  
  1514.         mov     dx, ax
  1515.  
  1516.         cmp     _mac_level, 0           ;check if nest level zero
  1517.         jne     _mccom1                 ;jump if so
  1518.  
  1519.         mov     _mac_symptr, 0          ;reset symbol table pointer
  1520.         mov     ax, _mac_symsiz         ;reset fixup table pointer
  1521.         mov     _mac_fixptr, ax         ;
  1522.         mov     _mac_codptr, 0          ;reset code pointer
  1523.  
  1524.         mov     _mac_undlen, 0          ;reset undefined symbol
  1525.         mov     _mac_undoff, 0          ;
  1526.  
  1527. ;--- allocate symbol table
  1528.  
  1529. _mccom1 cmp     _mac_symseg, 0          ;check if already allocated
  1530.         jnz     _mccom2
  1531.  
  1532.         push    dx
  1533.         mov     bp, MACRO_MEMORY        ;potential error
  1534.         mov     ax, _mac_symsiz
  1535.         call    MemAll                  ;allocate
  1536.         mov     _mac_symsiz, dx         ;save adjusted size
  1537.         pop     dx
  1538.         jc      _mccom8                 ;jump if error
  1539.         mov     _mac_symseg, ax         ;save it
  1540.  
  1541. ;--- open file
  1542.  
  1543. _mccom2 push    dx
  1544.         mov     ax, 1024
  1545.         mov     bx, di
  1546.         call    BufAll                  ;allocate buffer
  1547.         pop     ax
  1548.         jc      _mccom7
  1549.         mov     bp, MACRO_FILE          ;potential error
  1550.         mov     bx, di
  1551.         mov     cl, BUFFER_READ
  1552.         call    BufOpn                  ;open buffer
  1553.         jc      _mccom6                 ;exit if error
  1554.  
  1555. ;--- start up code
  1556.  
  1557.         cmp     _mac_level, 0           ;check if nest level zero
  1558.         jne     _mccom4                 ;skip startup code if not
  1559.  
  1560.         mov     ax, OFFSET _mac_Startup
  1561.         call    _mac_Code               ;store startup code
  1562.         jc      _mccom5                 ;jump if error
  1563.         jmps    _mccom4                 ;enter loop
  1564.  
  1565. ;--- loop for each token
  1566.  
  1567. _mccom3 call    _mac_Token              ;process token
  1568.         mov     bp, ax                  ;potential error
  1569.         jc      _mccom5                 ;jump if error
  1570.  
  1571. _mccom4 mov     ax, si
  1572.         mov     cx, MACRO_TOKEN
  1573.         mov     bx, di
  1574.         call    GetTok                  ;get next token
  1575.         jc      _mccom9                 ;jump if error
  1576.         or      ax, ax                  ;check if token returned
  1577.         jnz     _mccom3                 ;loop back if so
  1578.  
  1579. ;--- process fixups
  1580.  
  1581.         sub     bp, bp                  ;no error yet
  1582.         cmp     _mac_level, 0           ;check nest level
  1583.         jne     _mccom5                 ;skip fixups if not 0
  1584.  
  1585.         call    _mac_Fixups             ;perform fixups
  1586.         mov     bp, ax                  ;potential error
  1587.         jc      _mccom5                 ;jump if error
  1588.  
  1589.         call    MacRes                  ;reset execution
  1590.         sub     bp, bp                  ;no errors
  1591.  
  1592. ;---- close file
  1593.  
  1594. _mccom5 mov     bx, di
  1595.         call    BufClo                  ;close buffer
  1596. _mccom6 mov     bx, di
  1597.         call    BufRel                  ;release buffer
  1598.  
  1599. _mccom7 cmp     _mac_level, 0           ;check nest level
  1600.         jne     _mccom8                 ;skip deallocate if not zero
  1601.         cmp     MacBug, 0               ;check if preserve symbol table
  1602.         jne     _mccom8                 ;skip release if so
  1603.         mov     ax, _mac_symseg
  1604.         call    MemRel                  ;release symbol table
  1605.         mov     _mac_symseg, 0          ;zero segment
  1606.  
  1607. _mccom8 StkRel  BUFFER_RECORD,MACRO_TOKEN ;fix stack
  1608.         mov     ax, bp                  ;return error code in AX
  1609.         sub     dx, dx                  ;zero
  1610.         sub     dx, ax                  ;set carry if error
  1611.         pop     bp
  1612.         pop     si
  1613.         pop     di
  1614.         ret
  1615.  
  1616. ;--- error reading token
  1617.  
  1618. _mccom9 mov     bp, MACRO_LONGTOK
  1619.         or      ax, ax
  1620.         jz      _mccom5
  1621.         mov     bp, MACRO_FILE
  1622.         jmps    _mccom5
  1623.         ENDP
  1624.  
  1625. ;========================================
  1626. ; Reset the macro execution.
  1627.  
  1628. MacRes  PROC    NEAR
  1629.         mov     _mac_codsav, OFFSET _mcstar     ;entry point
  1630.         mov     ax, _mac_codsiz                 ;reset return pointer
  1631.         dec     ax
  1632.         dec     ax
  1633.         mov     _mac_retsav, ax
  1634.         mov     ax, _mac_stksiz         ;reset stack
  1635.         mov     _mac_stksav, ax
  1636.         ret
  1637.         ENDP
  1638.  
  1639. ;========================================
  1640. ; Run a loaded macro.
  1641. ;
  1642. ; Out: CY= set if macro BREAK, otherwise
  1643. ;      macro terminated.
  1644.  
  1645. MacRun  PROC    NEAR
  1646.         push    di              ;used in macro code
  1647.         push    si
  1648.         push    bp              ;used in macro code
  1649.  
  1650. ;--- save stack
  1651.  
  1652.         mov     ax, ss
  1653.         mov     _mac_oldseg, ax
  1654.         mov     _mac_oldoff, sp
  1655.  
  1656. ;--- switch to new stack
  1657.  
  1658.         cli
  1659.         mov     ax, _mac_stkseg
  1660.         mov     ss, ax
  1661.         mov     sp, _mac_stksav
  1662.         sti
  1663.  
  1664. ;--- transfer to routine
  1665.  
  1666.         mov     ax, _mac_codsav         ;entry point
  1667.         mov     si, _mac_retsav         ;return pointer
  1668.         mov     ds, _mac_codseg         ;segment
  1669.         seg     es
  1670.         call    _mac_start              ;enter code
  1671.  
  1672.         push    es
  1673.         pop     ds                      ;restore data segment
  1674.  
  1675. ;--- save state
  1676.  
  1677.         mov     _mac_codsav, ax         ;entry point
  1678.         mov     _mac_retsav, si         ;return pointer
  1679.         mov     _mac_stksav, sp         ;stack location
  1680.         jc      _mcrun1                 ;jump if BREAK
  1681.         sub     ax, ax                  ;save QUIT flag in AX
  1682.  
  1683. ;--- fix stack
  1684.  
  1685. _mcrun1 cli
  1686.         mov     dx, _mac_oldseg
  1687.         mov     ss, dx
  1688.         mov     sp, _mac_oldoff
  1689.         sti
  1690.  
  1691. ;--- finished
  1692.  
  1693.         sub     dx, dx
  1694.         sub     dx, ax          ;set carry if BREAK
  1695.         pop     bp
  1696.         pop     si
  1697.         pop     di
  1698.         ret
  1699.  
  1700. _mac_oldseg     DW      ?       ;original stack segment
  1701. _mac_oldoff     DW      ?       ;original stack offset
  1702.         ENDP
  1703.  
  1704. ;========================================
  1705. ; Load the top stack item from an
  1706. ; external routines.
  1707. ;
  1708. ; Out: AX= top item; DX= code/data
  1709. ;      segment.
  1710.  
  1711. MacLoa  PROC    NEAR
  1712.         push    si
  1713.         push    ds
  1714.         mov     ax, _mac_stkseg
  1715.         mov     si, _mac_stksav2
  1716.         mov     ds, ax
  1717.         cld
  1718.         lodsw
  1719.         xchg    ax, [si]
  1720.         pop     ds
  1721.         mov     _mac_stksav2, si
  1722.         mov     dx, _mac_codseg
  1723.         pop     si
  1724.         ret
  1725.         ENDP
  1726.  
  1727. ;========================================
  1728. ; Store the top stack item from an
  1729. ; external routines.
  1730. ;
  1731. ; In: AX= top item.
  1732.  
  1733. MacSto  PROC    NEAR
  1734.         push    si
  1735.         push    ds
  1736.         mov     dx, _mac_stkseg
  1737.         mov     si, _mac_stksav2
  1738.         mov     ds, dx
  1739.         xchg    ax, [si]
  1740.         dec     si
  1741.         dec     si
  1742.         mov     [si], ax
  1743.         pop     ds
  1744.         mov     _mac_stksav2, si
  1745.         pop     si
  1746.         ret
  1747.         ENDP
  1748.  
  1749. _macro1_end
  1750.